<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="author" content="lijinbo" />
    <title>255-字幕雨-代码雨</title>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
    </style>
  </head>

  <body>
    <div class="box">
      <p>
        <a href="https://www.douyin.com/video/7383665884440579328" target="_blank">参考-代码雨</a>
      </p>
      <canvas id="canvas"></canvas>
    </div>
    <script>
      /**@type {HTMLCanvasElement} */
      const canvas = document.getElementById('canvas')
      canvas.width = document.body.clientWidth
      canvas.height = 500
      // 上下文
      const ctx = canvas.getContext('2d')
      // 字体大小
      const fontSize = 16 * devicePixelRatio
      // 列宽
      const colWidth = fontSize
      // 列的数量
      const colCount = Math.floor(canvas.width / colWidth)
      // 每一列下一个文字是第几个文字
      const nextIndex = new Array(colCount).fill(0)
      // 绘制黑色画布
      ctx.fillStyle = 'rgba(0, 0, 0, 1)'
      ctx.fillRect(0, 0, canvas.width, canvas.height)

      function draw() {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
        ctx.fillRect(0, 0, canvas.width, canvas.height)
        for (let i = 0; i < colCount; i++) {
          const char = randomStringUnicode()
          ctx.fillStyle = randomColor()
          ctx.font = `${fontSize}px`
          const x = colWidth * i
          const index = nextIndex[i]
          const y = (index + 1) * fontSize
          ctx.fillText(char, x, y)
          if (y > canvas.height && Math.random() > 0.8) {
            nextIndex[i] = 0
          } else {
            nextIndex[i]++
          }
        }
      }

      setInterval(draw, 50)

      // 随机颜色
      function randomColor() {
        return `#${Math.floor(Math.random() * 0xffffff)
          .toString(16)
          .padEnd(6, '0')}`
      }
      // 随机字符串
      function randomStringUnicode() {
        const asciiRange = [33, 126]
        const charRange = [0x4e00, 0x9fa5]
        const getCode = (minCode, maxCode) => parseInt(Math.random() * (maxCode - minCode) + minCode)
        const range = Math.random() > 0.5 ? asciiRange : charRange
        return String.fromCharCode(getCode(...range))
      }
    </script>
  </body>
</html>
